﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using static Vanara.PInvoke.User32.RAWINPUT;
using Vanara.PInvoke;
using System.Threading;
using System.Web;

namespace GPDWin4GameBarPowerBackend.AIO.ServiceMain
{
    internal static class Extensions
    {
        public static void SendSuccess(this HttpListenerContext context,object obj = null)
        {
            string json = JsonConvert.SerializeObject(new
            {
                code=200,
                msg="OK",
                data=obj
            });
            context.Response.StatusCode = 200;
            context.Response.SendChunked = true;
            context.Response.ContentType = "application/json";
            using (StreamWriter sw = new StreamWriter(context.Response.OutputStream))
            {
                sw.Write(json);
                sw.Flush();
            }
            context.Response.Close();
        }
        public static void SendFail(this HttpListenerContext context,int code, string msg)
        {
            string json = JsonConvert.SerializeObject(new
            {
                code = code,
                msg = msg
            });
            context.Response.StatusCode = 200;
            context.Response.SendChunked = true;
            context.Response.ContentType = "application/json";
            using (StreamWriter sw = new StreamWriter(context.Response.OutputStream))
            {
                sw.Write(json);
                sw.Flush();
            }
            context.Response.Close();
        }
        public static void SendFail(this HttpListenerContext context, string msg)
        {
            context.SendFail(500,msg);
        }

        public static T GetPostedJson<T>(this HttpListenerContext context)
        {
            if(context.Request.HttpMethod.ToLower() == "post") {
                using(StreamReader sr = new StreamReader(context.Request.InputStream))
                {
                    return JsonConvert.DeserializeObject<T>(sr.ReadToEnd());
                }
            }
            else
            {
                throw new Exception("不支持GET方法");
            }
        }
    }

    public class ProcessHelper
    {
        private static string windir = "c:\\windows\\";
        public static List<string> getProcessLists()
        {
            List<string> list = new List<string>();
            windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows).ToLower();
            var sessionid = Kernel32.WTSGetActiveConsoleSessionId();
            var pids = Kernel32.EnumProcesses();
            if (sessionid != 0xffffffff)
            {

                foreach (var item in pids)
                {
                    var pid = item;

                    if (pid < 5) { continue; }
                    if(Kernel32.ProcessIdToSessionId(pid, out uint psid)){

                        if (psid != sessionid)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                    using (var phandle = Kernel32.OpenProcess((uint)Kernel32.ProcessAccess.PROCESS_QUERY_INFORMATION, false, pid))
                    {
                        var result = getProcessInfo(phandle);
                        if (result != null) { list.Add(result.ToString()); }
                    }
                }
            }
            else
            {

                foreach (var item in pids)
                {
                    var pid = item;
                    if (pid < 5) { continue; }
                    using (var phandle = Kernel32.OpenProcess((uint)Kernel32.ProcessAccess.PROCESS_QUERY_INFORMATION, false, pid))
                    {
                        var result = getProcessInfo(phandle);
                        if(result != null) { list.Add(result.ToString()); }
                    }
                }
            }
            return list.Distinct().ToList();
        }


        private static string getProcessInfo(Kernel32.SafeHPROCESS processHandle) 
        {
            StringBuilder sb = new StringBuilder();
            sb.EnsureCapacity(768);
            uint fileread = 768;
            if(Kernel32.QueryFullProcessImageName(processHandle,Kernel32.PROCESS_NAME.PROCESS_NAME_WIN32, sb,ref fileread))
            {
                var str = sb.ToString().ToLower();
                if (!str.StartsWith(windir))
                {
                    return str;
                }
               
            }
            return null;
            
        }

    }

    internal class HttpListenerExtend
    {
        Dictionary<string, Action<HttpListenerContext>> mappings;
        CancellationTokenSource stopSignal;
        private string staticResourcePath = "htdocs";
        private HttpListener listener;
        public HttpListenerExtend(HttpListener hl)
        {
            this.listener = hl;
            mappings = new Dictionary<string, Action<HttpListenerContext>>();
            stopSignal = new CancellationTokenSource();
        }
        public void setStaticResource(string resourcePath)
        {
            staticResourcePath = resourcePath;
            if (!Directory.Exists(resourcePath))
            {
                Directory.CreateDirectory(resourcePath);
            }
        }

        public void registerApiCall(string path,Action<HttpListenerContext> method)
        {
            mappings.Add(path, method);
        }

        public void startServerThread()
        {
            new Thread(ServerThread).Start();
        }

        private void ServerThread()
        {
            var cancellationToken = stopSignal.Token;
            try
            {
                while (true)
                {
                    var asyncGetContext = listener.GetContextAsync();

                    asyncGetContext.Wait(cancellationToken);
                    if (stopSignal.IsCancellationRequested)
                    {
                        throw new OperationCanceledException();
                    }
                    var context = asyncGetContext.Result;
                    if (context != null)
                    {
                        Task.Run(() =>
                        {
                            var currentContext = context;
                            ProcessRequest(currentContext);
                        });
                    }
                }
            }
            catch (OperationCanceledException)
            {
                listener.Prefixes.Clear();
                listener.Stop();
                listener = null;
            }

        }
        private void ProcessStaticResource(HttpListenerContext context)
        {
            var localPath = context.Request.Url.AbsolutePath;
            if (localPath.StartsWith("/")) { localPath = localPath.Substring(1); }
            if (localPath.EndsWith("/")) { localPath += "index.html"; }
            localPath = Path.Combine(staticResourcePath, localPath);
            if (!File.Exists(localPath) && Directory.Exists(localPath))
            {
                localPath += "/index.html";
            }
            if (File.Exists(localPath))
            {
                string mimetype = MimeMapping.GetMimeMapping(localPath);
                long contentLength = new FileInfo(localPath).Length;

                if (mimetype == null) { mimetype = "application/octet-stream"; }
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.ContentLength64 = contentLength;
                context.Response.ContentType = mimetype;
                context.Response.ContentEncoding = Encoding.UTF8;
                using (FileStream fs = File.OpenRead(localPath))
                {
                    fs.CopyTo(context.Response.OutputStream);
                }
                context.Response.Close();
            }
        }

        private void ProcessRequest(HttpListenerContext context)
        {
            if (!interceptApi(context))
            {
                ProcessStaticResource(context);
            }
        }



        public void stopServerThread() {
            stopSignal.Cancel();
        }

        public bool interceptApi(HttpListenerContext context)
        {
            var localPath = context.Request.Url.AbsolutePath;
            if (!localPath.StartsWith("/")) { localPath = "/" + localPath; }
            if (localPath.StartsWith("/api/"))
            {
                if (mappings.ContainsKey(localPath))
                {
                    try
                    {
                        mappings[localPath](context);
                    }catch (Exception ex) {
                        context.SendFail(500, ex.Message);
                        return true;
                    }
                }
            }
            return false;
        }
    }
}
